﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.Net;
using System.Net.NetworkInformation;

namespace System
{
    public class Native
    {

        [DllImport("Iphlpapi.dll")]
        static extern int GetTcpTable(IntPtr pTcpTable, ref int pdwSize, bool bOrder);

        [DllImport("Iphlpapi.dll")]
        static extern int SendARP(Int32 DestIP, Int32 SrcIP, ref Int64 MacAddr, ref Int32 PhyAddrLen);

        [DllImport("Ws2_32.dll")]
        static extern Int32 inet_addr(string ipaddr);

        [DllImport("Ws2_32.dll")]
        static extern ushort ntohs(ushort netshort);

        //SendArp获取MAC地址   
        public static string GetMacAddress(string macip)
        {
            StringBuilder strReturn = new StringBuilder();
            try
            {
                Int32 remote = inet_addr(macip);
                Int64 macinfo = new Int64();
                Int32 length = 6;
                SendARP(remote, 0, ref macinfo, ref length);
                string temp = System.Convert.ToString(macinfo, 16).PadLeft(12, '0').ToUpper();
                int x = 12;
                for (int i = 0; i < 6; i++)
                {
                    if (i == 5)
                    {
                        strReturn.Append(temp.Substring(x - 2, 2));
                    }
                    else
                    {
                        strReturn.Append(temp.Substring(x - 2, 2) + ":");
                    }
                    x -= 2;
                }

                return strReturn.ToString();
            }
            catch
            {
                return string.Empty;
            }
        }

        public static bool IsHostAlive(string strHostIP)
        {
            string strHostMac = GetMacAddress(strHostIP);
            return !string.IsNullOrEmpty(strHostMac);
        }

        public static MIB_TCPTABLE GetTcpTableInfo()
        {
            //声明一个指针准备接受Tcp连接信息   
            IntPtr hTcpTableData = IntPtr.Zero;

            //声明hTcpTableData指针所指向的内存缓冲区大小   
            int iBufferSize = 0;

            //声明MIB_TCPTABLE对象，作为返回值   
            MIB_TCPTABLE tcpTable = new MIB_TCPTABLE();

            //声明一个List对象来临时存放MIB_TCPROW对象   
            List<MIB_TCPROW> lstTcpRows = new List<MIB_TCPROW>();

            //调用API来获得真正的缓冲区大小，iBufferSize默认为0，   
            //这时调用API GetTcpTable会触发一个异常ERROR_INSUFFICIENT_BUFFER   
            //通过这个异常系统会把真正的缓冲长度返回   
            GetTcpTable(hTcpTableData, ref iBufferSize, false);

            //为托管指针在堆上分配内存   
            hTcpTableData = Marshal.AllocHGlobal(iBufferSize);

            //求得MIB_TCPROW对象的内存字节数   
            int iTcpRowLen = Marshal.SizeOf(typeof(MIB_TCPROW));

            //根据上面得到的缓冲区大小来推算MIB_TCPTABLE里的MIB_TCPROW数组长度   
            //下面用缓冲长度-sizeof(int)也就是去掉MIB_TCPTABLE里的成员dwNumEntries所占用的内存字节数   
            int aryTcpRowLength = (int)Math.Ceiling((double)(iBufferSize - sizeof(int)) / iTcpRowLen);

            //重新取得TcpTable的数据   
            GetTcpTable(hTcpTableData, ref iBufferSize, false);

            //下面是关键，由于MIB_TCPTABLE里的成员有一个是数组，而这个数组长度起初我们是不能确定的   
            //所以这里我们只能根据分配的指针来进行一些运算来推算出我们所要的数据   
            for (int i = 0; i < aryTcpRowLength; i++)
            {
                //hTcpTableData是指向MIB_TCPTABLE缓冲区的内存起始区域，由于其成员数据在内存中是顺序排列   
                //所以我们可以推断hTcpTableData+4(也就是sizeof(dwNumEntries)的长度)后就是MIB_TCPROW数组的第一个元素   
                IntPtr hTempTableRow = new IntPtr(hTcpTableData.ToInt32() + 4 + i * iTcpRowLen);
                MIB_TCPROW tcpRow = new MIB_TCPROW();
                tcpRow.dwLocalAddr = 0;
                tcpRow.dwLocalPort = 0;
                tcpRow.dwRemoteAddr = 0;
                tcpRow.dwRemotePort = 0;
                tcpRow.dwState = 0;

                //把指针数据拷贝到我们的结构对象里。   
                Marshal.PtrToStructure(hTempTableRow, tcpRow);
                lstTcpRows.Add(tcpRow);
            }

            tcpTable.dwNumEntries = lstTcpRows.Count;
            tcpTable.table = new MIB_TCPROW[lstTcpRows.Count];
            lstTcpRows.CopyTo(tcpTable.table);
            return tcpTable;
        }


        public static int KillTcp(int max, bool ifKill, Dictionary<string, string> writeList, out int tcpCount, string sPorts, ref string list)
        {
            int result = 0;

            IntPtr hTcpTableData = IntPtr.Zero;
            int iBufferSize = 0;
            List<MIB_TCPROW> lstTcpRows = new List<MIB_TCPROW>();
            GetTcpTable(hTcpTableData, ref iBufferSize, false);
            hTcpTableData = Marshal.AllocHGlobal(iBufferSize);
            int iTcpRowLen = Marshal.SizeOf(typeof(MIB_TCPROW));
            int aryTcpRowLength = (int)Math.Ceiling((double)(iBufferSize - sizeof(int)) / iTcpRowLen);
            GetTcpTable(hTcpTableData, ref iBufferSize, false);

            tcpCount = aryTcpRowLength;

            if (aryTcpRowLength > max)
            {
                for (int i = 0; i < aryTcpRowLength; i++)
                {
                    IntPtr hTempTableRow = new IntPtr(hTcpTableData.ToInt32() + 4 + i * iTcpRowLen);
                    MIB_TCPROW tcpRow = new MIB_TCPROW();
                    tcpRow.dwLocalAddr = 0;
                    tcpRow.dwLocalPort = 0;
                    tcpRow.dwRemoteAddr = 0;
                    tcpRow.dwRemotePort = 0;
                    tcpRow.dwState = 0;
                    Marshal.PtrToStructure(hTempTableRow, tcpRow);

                    list += Native.GetIpAddress(tcpRow.dwLocalAddr) + ":" + Native.GetTcpPort(tcpRow.dwLocalPort).ToString() + "  " + Native.GetIpAddress(tcpRow.dwRemoteAddr) + ":" + Native.GetTcpPort(tcpRow.dwRemotePort).ToString() + "  " + tcpRow.dwState.ToString() + "\r\n";

                    if (ifKill && !writeList.ContainsKey(Native.GetIpAddress(tcpRow.dwRemoteAddr)) && CheckPort(Native.GetTcpPort(tcpRow.dwLocalPort), sPorts))
                    {
                        if (TcpManager.Kill(tcpRow))
                        {
                            result++;
                        }
                    }
                }
            }

            return result;
        }

        public static bool CheckPort(int port, string sPorts)
        {
            if (sPorts == "-1")
                return true;
            string[] ports = sPorts.Split(',');
            bool isport = false;
            foreach (string p in ports)
            {
                try
                {
                    if (port == Convert.ToInt32(p))
                        isport = true;
                    break;
                }
                catch { }
            }
            return isport;
        }

        //public static string GetIpAddress(long ipAddrs)
        //{
        //    try
        //    {
        //        System.Net.IPAddress ipAddress = new System.Net.IPAddress(ipAddrs);
        //        return ipAddress.ToString();
        //    }
        //    catch
        //    {
        //        return ipAddrs.ToString();
        //    }
        //}
        //public static ushort GetTcpPort(int tcpPort)
        //{
        //    return ntohs((ushort)tcpPort);
        //}

        public static string GetIpAddress(int Address)
        {
            byte[] IpParts = BitConverter.GetBytes(Address);

            StringBuilder builder = new StringBuilder();
            builder.Append(IpParts[0].ToString());
            builder.Append(".");
            builder.Append(IpParts[1].ToString());
            builder.Append(".");
            builder.Append(IpParts[2].ToString());
            builder.Append(".");
            builder.Append(IpParts[3].ToString());

            return builder.ToString();
        }

        public static int GetTcpPort(int Port)
        {
            return Port / 256 + (Port % 256) * 256;
        }

        public static bool IsPortBusy(int port)
        {
            MIB_TCPTABLE tcpTableData = GetTcpTableInfo();
            return false;
        }

    }
}